package com.jingdianjichi.gateway.auth;

import cn.dev33.satoken.stp.StpInterface;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.jingdianjichi.gateway.entity.AuthPermission;
import com.jingdianjichi.gateway.entity.AuthRole;
import com.jingdianjichi.gateway.utils.RedisUtil;
import org.checkerframework.checker.index.qual.GTENegativeOne;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 自定义权限认证接口扩展
 */
@Component
public class StpInterfaceImpl implements StpInterface {

    //用工具类去交互
    @Resource
    private RedisUtil redisUtil;

    //权限,我们是隔离的这两个,我们在存入Redis的时候也要这样存储的
    private String authPermissionPrefix="auth.permission";

    //角色
    private String authRolePrefix="auth.role";

    //返回权限列表loginId就是用户id,loginType这个就是登录的方式
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        /*
             1.直接和数据库交互
             2.直接和redis交互(完全依靠缓存,缓存和数据库的数据一致性的问题亲)
             3.redis没有的话去,调用数据库获取
             4.redis没有的话去,调用auth认证服务获取(一定要处理好缓存三件套的)
                /我们用2,这样做数据库缓存一致性的问题,我们全部依赖缓存,这样我们的持久化要顶住,数据同步要顶的住
         */

        return getAuth(authPermissionPrefix,loginId.toString());
    }

    //返回角色列表
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        return getAuth(authRolePrefix, loginId.toString());
    }


    //抽取方法,去数据库那value,如果是复杂业务逻辑的话这里就不能进行抽取了
    private List<String> getAuth(String prefix,String loginId){
        //System.out.println("进断电了======================");

        //构建key,所以我们在寸的时候也要这样去数据库寸的
        String authKey = redisUtil.buildKey(prefix,loginId);

        String authValue = redisUtil.get(authKey);

        //空的直接返回
        if (StringUtils.isBlank(authValue)){
            return Collections.emptyList();
        }

        List<String> authList=new ArrayList<>();
        if (authRolePrefix.equals(prefix))
        {
            List<AuthRole> roleList = new Gson().fromJson(authValue, new TypeToken<List<AuthRole>>() {
            }.getType());//序列化回来

            authList=roleList.stream().map(AuthRole::getRoleKey).collect(Collectors.toList());
        }
        else if (authPermissionPrefix.equals(prefix))
        {
            List<AuthPermission> permissionList = new Gson().fromJson(authValue, new TypeToken<List<AuthPermission>>() {
            }.getType());//序列化回来

            authList=permissionList.stream().map(AuthPermission::getPermissionKey).collect(Collectors.toList());
        }


        //不是空的我们去做解析序列化,我们这里使用的是Gson你用jackSon也是可以的
        //List<String> authList = new Gson().fromJson(authValue, List.class);

        return authList;
    }

    /**
     * TODO
     *   我们这里使用的方案是完全的信任缓存,所以对于缓存和数据库的一致性问题我们是你解决的问题是比较少的
     *      /你可以去看文档
     *
     *   SpringSecurity默认把用户的角色和权限放到上下文中,sa-token不是,人家是用一次查一次
     */

}
